
from solv import Job
import solv
import re

# TODO: move much of this to Pkgr
import logging
logger = logging.getLogger('pkgr.jobs')

def validarch(pool, arch):
    if not arch:
        return False
    id = pool.str2id(arch, False)
    if not id:
        return False
    return pool.isknownarch(id)

def limitjobs(pool, jobs, flags, evrstr):
    njobs = []
    evr = pool.str2id(evrstr)
    for j in jobs:
        how = j.how
        sel = how & Job.SOLVER_SELECTMASK
        what = pool.rel2id(j.what, evr, flags)
        if flags == solv.REL_ARCH:
            how |= Job.SOLVER_SETARCH
        elif flags == solv.REL_EQ and sel == Job.SOLVER_SOLVABLE_NAME:
            if evrstr.find('-') >= 0:
                how |= Job.SOLVER_SETEVR
            else:
                how |= Job.SOLVER_SETEV
        njobs.append(pool.Job(how, what))
    return njobs

def limitjobs_evrarch(pool, jobs, flags, evrstr):
    m = re.match(r'(.+)\.(.+?)$', evrstr)
    if m and validarch(pool, m.group(2)):
        jobs = limitjobs(pool, jobs, solv.REL_ARCH, m.group(2))
        evrstr = m.group(1)
    return limitjobs(pool, jobs, flags, evrstr)

def mkjobs_filelist(pool, cmd, arg):
    logger.debug('mkjobs_filelist %s %s', cmd, arg)
    if re.search(r'[[*?]', arg):
        type = Dataiterator.SEARCH_GLOB
    else:
        type = Dataiterator.SEARCH_STRING
    if cmd == 'erase':
        di = pool.installed.Dataiterator(0, solv.SOLVABLE_FILELIST, arg, type | solv.Dataiterator.SEARCH_FILES|solv.Dataiterator.SEARCH_COMPLETE_FILELIST)
    else:
        di = pool.Dataiterator(0, solv.SOLVABLE_FILELIST, arg, type | solv.Dataiterator.SEARCH_FILES|solv.Dataiterator.SEARCH_COMPLETE_FILELIST)
    matches = []
    for d in di:
        s = d.solvable
        if s and s.installable():
            matches.append(s.id)
            di.skip_solvable()  # one match is enough
    if matches:
        print "[using file list match for '%s']" % arg
        if len(matches) > 1:
            return [ pool.Job(Job.SOLVER_SOLVABLE_ONE_OF, pool.towhatprovides(matches)) ]
        else:
            return [ pool.Job(Job.SOLVER_SOLVABLE | Job.SOLVER_NOAUTOSET, matches[0]) ]
    return []

def mkjobs_rel(pool, cmd, name, rel, evr):
    logger.debug('mkjobs rel %s %s %s %s', cmd, name, rel, evr)
    flags = 0
    if rel.find('<') >= 0: flags |= solv.REL_LT
    if rel.find('=') >= 0: flags |= solv.REL_EQ 
    if rel.find('>') >= 0: flags |= solv.REL_GT
    jobs = depglob(pool, name, True, True)
    if jobs:
        return limitjobs(pool, jobs, flags, evr)
    m = re.match(r'(.+)\.(.+?)$', name)
    if m and validarch(pool, m.group(2)):
        jobs = depglob(pool, m.group(1), True, True)
        if jobs:
            jobs = limitjobs(pool, jobs, solv.REL_ARCH, m.group(2))
            return limitjobs(pool, jobs, flags, evr)
    return []

def mkjobs_nevra(pool, cmd, arg):
    logger.debug('mkjobs nevra %s %s', cmd, arg)
    jobs = depglob(pool, arg, True, True)
    if jobs:
        logger.debug('return depglob: %s', jobs)
        return jobs
    m = re.match(r'(.+)\.(.+?)$', arg)
    if m and validarch(pool, m.group(2)):
        jobs = depglob(pool, m.group(1), True, True)
        if jobs:
            logger.debug('limitjobs arch %s %s', jobs, m.group(2))
            return limitjobs(pool, jobs, solv.REL_ARCH, m.group(2))
    m = re.match(r'(.+)-([^\.\-]+)$', arg)
    if m:
        jobs = depglob(pool, m.group(1), True, False)
        if jobs:
            logger.debug('limitjobs version %s %s', jobs, m.group(2))
            return limitjobs_evrarch(pool, jobs, solv.REL_EQ, m.group(2))
    m = re.match(r'(.+)-(.+?-.+?)$', arg)
    if m:
        jobs = depglob(pool, m.group(1), True, False)
        if jobs:
            filtered = limitjobs_evrarch(pool, jobs, solv.REL_EQ, m.group(2))
            logger.debug('limitjobs release %s %s %s', jobs, m.group(2), filtered)
            return filtered
    return []

def mkjobs(pool, cmd, arg):
    logger.debug('mkjobs %s %s', cmd, arg)
    if len(arg) and arg[0] == '/':
        jobs = mkjobs_filelist(pool, cmd, arg)
        if jobs:
            return jobs
            
    m = re.match(r'(.+?)\s*([<=>]+)\s*(.+?)$', arg)
    if m:
        return mkjobs_rel(pool, cmd, m.group(1), m.group(2), m.group(3))
    else:
        return mkjobs_nevra(pool, cmd, arg)
            
def depglob(pool, name, globname, globdep):
    logger.debug('depglob %s', name)
    id = pool.str2id(name, False)
    if id:
        match = False
        for s in pool.whatprovides(id):
            if globname and s.nameid == id:
                return [ pool.Job(Job.SOLVER_SOLVABLE_NAME, id) ]
            match = True
        if match:
            if globname and globdep:
                print "[using capability match for '%s']" % name
            return [ pool.Job(Job.SOLVER_SOLVABLE_PROVIDES, id) ]
    if not re.search(r'[[*?]', name):
        return []
    if globname:
        # try name glob
        idmatches = {}
        for d in pool.Dataiterator(0, solv.SOLVABLE_NAME, name, solv.Dataiterator.SEARCH_GLOB):
            s = d.solvable
            if s.installable():
                idmatches[s.nameid] = True
        if idmatches:
            return [ pool.Job(Job.SOLVER_SOLVABLE_NAME, id) for id in sorted(idmatches.keys()) ]
    if globdep:
        # try dependency glob
        idmatches = pool.matchprovidingids(name, solv.Dataiterator.SEARCH_GLOB)
        if idmatches:
            print "[using capability match for '%s']" % name
            return [ pool.Job(Job.SOLVER_SOLVABLE_PROVIDES, id) for id in sorted(idmatches) ]
    return []
